// 标识组件是不是第一次 mount 如果不是的化需要他走 update 逻辑
let isMount = true
// 组件中可能有多个 hook
// 所以用变量标记一下当前正在处理的是哪一个 hook （该变量相当于一个快捷指针，指向了链表中的某一个 hook）
let workInProgressHook = null

// 组件对应的 fiber
// 每个组件都会有一个 fiber
const fiber = {
  stateNode: App,
  // 组件对应的 hook 链表（默认指向第一个 hook）
  // 对于函数组件该值保存的是 hooks 的数据
  // 对于 class 组件则保存的是 class 的 state
  // 由于 hook 可以有多个 所以这里应该是个链表结构 可以通过 next 访问到下一个 hook
  // 链表中的每一项对应的是组件中的每一个 hook 中的数据
  memoizedState: null
}

function useState(initialState) {
  // 由于组件可能有多个 hook 所以需要找出当前正在运行的是哪一个 hook
  let hook

  // 如果是第一次挂在组件 由于 fiber 中的状态值为 null 所以需要进行初始化
  if(isMount) {
    hook = {
      // hook 中保存着实际的值
      memoizedState: initialState,
      // 每一个 hook 除了有初始状态，它还有后续更新操作产生的状态
      queue: {
        // pending 是一个链表指针（默认指向最新 update 操作）
        // 链表因为更新操作可以连续调用多次
        // 循环是因为 react 操作中分优先级，这样可以方便控制
        // 默认指向最后的更新操作
        // Action1 -> Action2 -> Action3 -> Action1
        pending: null
      },
      next: null
    }

    // 第一次挂载 且 执行第一个 hook 时
    if(!fiber.memoizedState) {
      fiber.memoizedState = hook
      // workInProgressHook = hook
    } else {
      // 第一次挂载 且 执行非第一个 hook 时
      workInProgressHook.next = hook
      // workInProgressHook = hook
    }

    // 移动到链表的下一个
    workInProgressHook = hook

  } else {
    // 组件 update 逻辑
    // 因为挂载阶段已经有了链表 所以更新阶段可以直接取到 hook
    hook = workInProgressHook
    // 处理完当前 hook 后，指向下一个 hook
    workInProgressHook = workInProgressHook.next
  }

  // 计算状态
  let baseState = hook.memoizedState
  // 是否已经存在更新链表
  if(hook.queue.pending) {
    const head = hook.queue.pending.next
    // 由于 pending 默认指向最新的更新 我们需要从第一个更新开始计算新状态
    let firstUpdate = hook.queue.pending.next

    // 计算新状态
    do {
      // 基于旧状态计算新状态（这里默认用户的 action 是一个回调函数）
      baseState = firstUpdate.action(baseState)
      // 指针指向下一个更新操作
      firstUpdate = firstUpdate.next

    } while(head !== firstUpdate)  // 由于是环状链表 所以通过是否回到头部做跳出判断

    // 当更新操作执行完后需要清空，以防下一次组件执行时还有上一次的缓存数据
    hook.queue.pending = null
  }

  // hook 保存最新的状态
  hook.memoizedState = baseState

  const _dispatchAction = (action) => {
    dispatchAction(hook.queue, action)
  }
  return [
    baseState,
    _dispatchAction
  ]
}

// hook 的更新操作
function dispatchAction(queue, action) {
  // 新的更新操作
  const newUpdate = {
    action,
    next: null
  }

  // 如果该 hook 还没有更新操作
  if(queue.pending === null) {
    // 指向自己 形成环
    newUpdate.next = newUpdate
  } else {
    // A1 -> A2  A3
    // 最新的操作,如上 A3 指向开头 A1
    newUpdate.next = queue.pending.next
    // A2 指向新的 A3
    queue.pending.next = newUpdate
  }

  queue.pending = newUpdate

  // 修改状态会触发更新
  schedule()
}

// 当改变状态时需要重新调度使组件得以跟新
function schedule() {
  // 重新执行组件前 需要将 hook 复位一下
  workInProgressHook = fiber.memoizedState

  const dom = fiber.stateNode()
  isMount = false

  return dom
}

// 模拟一个组件
function App() {
  const [num, updateNum] = useState(0)
  const [num2, updateNum2] = useState(10)

  console.log('render', 'isMount:', isMount, 'num:', num, 'num2:', num2)

  return {
    onClick: () => {
      updateNum((n) => {
        return n + 1
      })
    },
    onClick2: () => {
      updateNum2((n) => {
        return n + 10
      })
    }
  }
}

window.app = schedule()